package com.mts.javacommon;

import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.google.common.collect.Lists;
import java.util.*;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class TemplateCodeGenerator {

  private static final ModuleInfo javaCommonModule =
      new ModuleInfo()
          .setModuleName("java-common")
          .setSourcePath("src/main/java")
          .setBusinessLevelName("common");

  private static final ModuleInfo repositoryModule =
      new ModuleInfo()
          .setModuleName("indicator-jpa")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("repository");

  private static final ModuleInfo searchModule =
      new ModuleInfo()
          .setSourcePath("src/main/kotlin")
          .setModuleName("indicator-common")
          .setBusinessLevelName("search");

  private static final ModuleInfo voModule =
      new ModuleInfo()
          .setSourcePath("src/main/kotlin")
          .setModuleName("indicator-common")
          .setBusinessLevelName("vo");

  private static final ModuleInfo converterModule =
      new ModuleInfo()
          .setModuleName("indicator-common")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("converter");

  private static final ModuleInfo entityModule =
      new ModuleInfo()
          .setModuleName("indicator-jpa")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("entity");

  private static final ModuleInfo serviceModule =
      new ModuleInfo()
          .setModuleName("indicator-server")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("service");

  private static final ModuleInfo serviceImplModule =
      new ModuleInfo()
          .setModuleName("indicator-server")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("service/impl");

  private static final ModuleInfo controllerModule =
      new ModuleInfo()
          .setModuleName("indicator-server")
          .setSourcePath("src/main/kotlin")
          .setBusinessLevelName("controller");

  // 全局配置
  private static final GlobalConfig globalConfig = CodeGeneratorConfig.getGlobalConfig();

  // 数据源配置
  private static final DataSourceConfig dataSourceConfig =
      CodeGeneratorConfig.getDataSourceConfig();

  private static final String SLATH = "/";
  private static final String DOT = ".";

  public static void main(String[] args) {
    String module = "";
    // 包名策略
    PackageConfig packageConfig = new PackageConfig();
    packageConfig
        .setParent("com.mts")
        .setEntity(repositoryModule.getModuleName().replace("-", ""))
        .setMapper("repository" + module)
        .setService("service" + module)
        .setServiceImpl("service" + module + ".impl")
        .setController("controller" + module)
        .setXml("dao" + module + ".xml");

    // 模板配置
    TemplateConfig templateConfig = new TemplateConfig();
    // 添加自定义的模板
    templateConfig
        .setController("/templates/vms/JPAController.java")
        //        .setServiceImpl("/templates/vms/JPAServiceImpl.java")
        .setService("/templates/vms/JPAService.java")
        // .setEntity("/templates/vms/Entity.java");
        .setEntity("/templates/vms/JPAEntity.java")
        .setMapper(null)
        // JPA 不生成 xml
        .setXml(null);
    boolean genDTO = true; // 是否生成DTO
    templateConfig.disable(
        //                 TemplateType.CONTROLLER // , // 不生成Controller
        TemplateType.SERVICE // 不生成Service
        //                 TemplateType.MAPPER // 不生成Mapper
        //                 TemplateType.XML // 不生成Mapper.xml
        );

    // 自定义配置
    List<FileOutConfig> fileOutConfigs = new ArrayList<>();
    // 添加生成对应于Entity的DTO
    if (genDTO) {
      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/JPARepositoryKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(repositoryModule, packageConfig, tableInfo);
            }
          });
      // search
      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/SearchVoKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(searchModule, packageConfig, tableInfo);
            }
          });

      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/VoKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(voModule, packageConfig, tableInfo);
            }
          });

      // converter
      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/ConverterKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(converterModule, packageConfig, tableInfo);
            }
          });

      // entity
      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/JPAEntityKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(entityModule, packageConfig, tableInfo);
            }
          });

      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/JPAServiceKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(serviceModule, packageConfig, tableInfo);
            }
          });
      // service impl
      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/JPAServiceImplKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(serviceImplModule, packageConfig, tableInfo);
            }
          });

      fileOutConfigs.add(
          new FileOutConfig("/templates/vms/kotlin/JPAControllerKt.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
              return getGeneratedPath(controllerModule, packageConfig, tableInfo);
            }
          });
    }
    // 添加自定义配置中的参数
    InjectionConfig injectionConfig =
        new InjectionConfig() {
          @Override
          public void initMap() {
            Map<String, Object> map = new HashMap<>();
            map.put("lombok", true); // 启用lombok，在模板中使用${cfg.lombok}
            map.put(
                "jpaBasePkg",
                packageConfig.getParent()
                    + DOT
                    + javaCommonModule.getModuleName().replaceAll("-", "")
                    + ".jpabase");
            // map.put("exceptionPkg", packageConfig.getParent() + ".exception");
            map.put(
                "exceptionPkg",
                packageConfig.getParent()
                    + DOT
                    + javaCommonModule.getModuleName().replaceAll("-", "")
                    + ".exception");
            map.put(
                "converterPkg",
                packageConfig.getParent()
                    + DOT
                    + converterModule.getModuleName()); // 生成Repository时的包路径
            map.put(
                "repositoryPkg",
                packageConfig.getParent()
                    + DOT
                    + repositoryModule.getModuleName()); // 生成Repository时的包路径
            map.put(
                "voPkg", packageConfig.getParent() + DOT + voModule.getModuleName()); // 生成Vo时的包路径
            map.put(
                "searchPkg",
                packageConfig.getParent() + DOT + searchModule.getModuleName()); // 生成Search时的包路径

            map.put(
                "entityPkg",
                packageConfig.getParent() + DOT + entityModule.getModuleName()); // 生成Search时的包路径
            map.put(
                "servicePkg",
                packageConfig.getParent() + DOT + serviceModule.getModuleName()); // 生成Search时的包路径
            map.put(
                "serviceImplPkg",
                packageConfig.getParent()
                    + DOT
                    + serviceImplModule.getModuleName()); // 生成Search时的包路径
            map.put(
                "controllerPkg",
                packageConfig.getParent()
                    + DOT
                    + controllerModule.getModuleName()); // 生成Search时的包路径

            //            map.put("searchPkg", packageConfig.getParent() + ".search" + module); //
            // 生成Vo时的包路径
            map.put("swaggerTagName", "业务接口");
            map.put("servicePort", "8082");
            map.put(
                "commonCols",
                Lists.newArrayList(
                    "id", "create_time", "update_time", "create_by", "update_by")); // 所有实体都具有基础属性
            map.put(
                "withoutToEntityCols",
                Lists.newArrayList(
                    "create_time", "update_time", "create_by", "update_by")); // 所有实体都具有基础属性
            map.put(
                "entityExcludePkgs",
                Lists.newArrayList(
                    "com.baomidou.mybatisplus.annotation.TableId",
                    "com.baomidou.mybatisplus.annotation.IdType",
                    "java.io.Serializable")); // Entity中不引入的包
            this.setMap(map);
          }
        };
    injectionConfig.setFileOutConfigList(fileOutConfigs);

    // 开始生成
    AutoGenerator autoGenerator = new AutoGenerator();
    autoGenerator
        .setDataSource(dataSourceConfig)
        .setPackageInfo(packageConfig)
        .setTemplate(templateConfig)
        .setGlobalConfig(globalConfig)
        .setCfg(injectionConfig)
        .setStrategy(CodeGeneratorConfig.getStrategyConfig());
    autoGenerator.execute();
  }

  public static String capitalizeFirst(String str) {
    if (str == null || str.isEmpty()) {
      return str;
    }
    StringBuilder sb = new StringBuilder();
    // 拆分成 ["service", "impl"]
    String[] parts = str.split("/");
    for (String part : parts) {
      if (!part.isEmpty()) {
        sb.append(part.substring(0, 1).toUpperCase()).append(part.substring(1));
      }
    }
    return sb.toString();
  }

  static String getGeneratedPath(
      ModuleInfo moduleInfo, PackageConfig packageConfig, TableInfo tableInfo) {
    String businessLevelName = moduleInfo.getBusinessLevelName();
    capitalizeFirst(businessLevelName);
    String fileType = moduleInfo.getSourcePath().contains("kotlin") ? ".kt" : ".java";
    return globalConfig.getOutputDir()
        + moduleInfo.getSourceGeneratePath(packageConfig)
        + tableInfo.getEntityName().toLowerCase()
        + SLATH
        + moduleInfo.getBusinessLevelName()
        + SLATH
        + tableInfo.getEntityName()
        + capitalizeFirst(businessLevelName)
        + fileType;
  }

  @Accessors(chain = true)
  @Data
  static class ModuleInfo {
    String sourcePath = "";
    String moduleName = "";
    String businessLevelName = "";

    String getModulePath() {
      return moduleName + "/" + sourcePath + "/";
    }

    String getSourceGeneratePath(PackageConfig packageConfig) {
      return getModulePath()
          + packageConfig.getParent().replaceAll("\\.", "/")
          + SLATH
          + getModuleName()
          + SLATH;
    }

    String getModuleName() {
      return moduleName.replace("-", "");
    }
  }
}

//
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/BaseEntity.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//
//                    return globalConfig.getOutputDir()
//                            + "/" + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/"
//                            + "BaseEntity.java";
//                }
//            });
//
//            //JpaAuditorAware
//            fileOutConfigs.add(new FileOutConfig("/templates/vms/JpaAuditorAware.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//
//                    return globalConfig.getOutputDir()
//                            + "/" + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/"
//                            + "JpaAuditorAware.java";
//                }
//            });
//
//            //baseVo
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/BaseVo.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//
//                    return globalConfig.getOutputDir()
//                            + "/" + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/"
//                            + "BaseVo.java";
//                }
//            });
//

// PageVo
//
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/PageVo.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "PageVo.java";
//                }
//            });
//
//            //PageUtil
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/PageUtil.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "PageUtil.java";
//                }
//            });
//
//            //ResultVo
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/ResultVo.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "ResultVo.java";
//                }
//            });
//
//            //ResultVoUtil
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/ResultVoUtil.java.vm")
// {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "ResultVoUtil.java";
//                }
//            });
//
//            //BaseService
//            fileOutConfigs.add(new FileOutConfig("/templates/basevms/BaseService.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "BaseService.java";
//                }
//            });
//
//            //ConditionService
//            fileOutConfigs.add(new
// FileOutConfig("/templates/basevms/ConditionService.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "ConditionService.java";
//                }
//            });
//
//            //QueryCondition
//            fileOutConfigs.add(new
// FileOutConfig("/templates/basevms/QueryCondition.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/jpabase/" + module.replace(".", "") + "/"
//                            + "QueryCondition.java";
//                }
//            });
//
//            fileOutConfigs.add(new
// FileOutConfig("/templates/exceptionvms/BaseErrorInterface.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/exception/" + module.replace(".", "") + "/"
//                            + "BaseErrorInterface.java";
//                }
//            });
//
//            fileOutConfigs.add(new
// FileOutConfig("/templates/exceptionvms/BizException.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/exception/" + module.replace(".", "") + "/"
//                            + "BizException.java";
//                }
//            });
//
//
//            fileOutConfigs.add(new
// FileOutConfig("/templates/exceptionvms/ExceptionEnum.java.vm") {
//                @Override
//                public String outputFile(TableInfo tableInfo) {
//                    return globalConfig.getOutputDir()
//                            + "/"
//                            + packageConfig.getParent().replaceAll("\\.", "/")
//                            + "/exception/" + module.replace(".", "") + "/"
//                            + "ExceptionEnum.java";
//                }
//            });
